// nettest.cc 
//	Test out message delivery between two "Nachos" machines,
//	using the Post Office to coordinate delivery.
//
//	Two caveats:
//	  1. Two copies of Nachos must be running, with machine ID's 0 and 1:
//		./nachos -m 0 -o 1 &
//		./nachos -m 1 -o 0 &
//
//	  2. You need an implementation of condition variables,
//	     which is *not* provided as part of the baseline threads 
//	     implementation.  The Post Office won't work without
//	     a correct implementation of condition variables.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"

#include "system.h"
#include "network.h"
#include "post.h"
#include "interrupt.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

// Test out message delivery, by doing the following:
//	1. send a message to the machine with ID "farAddr", at mail box #0
//	2. wait for the other machine's message to arrive (in our mailbox #0)
//	3. send an acknowledgment for the other machine's message
//	4. wait for an acknowledgement from the other machine to our 
//	    original message

void MailTest(int farAddr)
{
    PacketHeader outPktHdr, inPktHdr;
    MailHeader outMailHdr, inMailHdr;
    char *data = "Hello there!";
    char *ack = "Got it!";
    char buffer[MaxMailSize];

    // construct packet, mail header for original message
    // To: destination machine, mailbox 0
    // From: our machine, reply to: mailbox 1
    outPktHdr.to = farAddr;		
    outMailHdr.to = 0;
    outMailHdr.from = 1;
    outMailHdr.length = strlen(data) + 1;

    // Send the first message
    bool success = postOffice->Send(outPktHdr, outMailHdr, data); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the first message from the other machine
    postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);

    // Send acknowledgement to the other machine (using "reply to" mailbox
    // in the message that just arrived
    outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    outMailHdr.length = strlen(ack) + 1;
    success = postOffice->Send(outPktHdr, outMailHdr, ack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }

    // Wait for the ack from the other machine to the first message we sent.
    postOffice->Receive(1, &inPktHdr, &inMailHdr, buffer);
    printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);

    // Then we're done!
    interrupt->Halt();
}


void createLock(char* LockName, PacketHeader MachineID, MailHeader BoxID){
	ServerLock *lock;
	bool exist = false;
	int id;
	int i;
	char *nack = "Error: the number of locks reaches the maximum value!";
	lockServerTableLock->Acquire();
	lock = new ServerLock(LockName);
	for(i=0; i<MAX_LOCKS; i++){
		if (kernelServerLocks[i].Serverlock!=NULL && !strcmp(kernelServerLocks[i].Serverlock->name,LockName)){
			exist = true;
		  break;
		}
	}
	if (exist == true){
		delete lock;
		printf("Lock '%s' already exist\n", kernelServerLocks[i].Serverlock->name);
		BoxID.from = 0;
		char *iddata = new char[25];   
  	sprintf(iddata, "%d", i);
		BoxID.length = strlen(iddata) + 1;
		bool success = postOffice->Send(MachineID, BoxID, iddata); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
	}
	else{
		id = lockServerMap->Find();
		if (id < 0) {
		printf("Error: the number of locks reaches the maximum value\n");
		BoxID.from = 0;
		BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
		}
		char *iddata = new char[25];   
  	sprintf(iddata, "%d", id);
		kernelServerLocks[id].Serverlock = lock;
		kernelServerLocks[id].isToBeDeleted = FALSE;
		kernelServerLocks[id].addr = currentThread->space;
		BoxID.from = 0;
		BoxID.length = strlen(iddata) + 1;
		bool success = postOffice->Send(MachineID, BoxID, iddata); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
    delete[] iddata;
	}
	lockServerTableLock->Release();
}

void destoryLcok(int id, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Destroy Lock Fail!";
	if (id < 0) {
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		printf("Error: the lock id %d is invalid\n", id);
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	char *ack = "Destroy Lock success!";
	char *ack2 = "Destroy Lock after release!";
	lockServerTableLock->Acquire();
	if (kernelServerLocks[id].Serverlock == NULL) {
		printf("Error: The lock has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		lockServerTableLock->Release();
		return;
	}
	if (kernelServerLocks[id].Serverlock->getStatus() == FREE) {
		// No threads are waiting
		// delete the lock
		ServerLock *lock = kernelServerLocks[id].Serverlock;
		delete lock;
		kernelServerLocks[id].Serverlock = NULL;
		kernelServerLocks[id].addr = NULL;
		lockServerMap->Clear(id);
		BoxID.from = 0;
		BoxID.length = strlen(ack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, ack); 

		if ( !success ) {
			printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
			interrupt->Halt();
			}
	}else {
		// Some one is waiting
		// delete it later
		kernelServerLocks[id].isToBeDeleted = TRUE;
		BoxID.from = 0;
		BoxID.length = strlen(ack2) + 1;
		bool success = postOffice->Send(MachineID, BoxID, ack2); 

		if ( !success ) {
			printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
			interrupt->Halt();
			}
	}
	
	lockServerTableLock->Release();
}

void acquireLcok(int id, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Acquire Lock Fail!";
	char *nack2 = "You are already the lock owner!";
	if (id < 0) {
		printf("Error: the lock id %d is invalid\n", id);
		BoxID.from = 0;
		BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	char *iddata = new char[25];   
  sprintf(iddata, "%d", id);
  BoxID.from = 0;
  BoxID.length = strlen(iddata) + 1;
  ACKInfor *Newmsg = new ACKInfor;
	Newmsg->outPktHdr = MachineID;
	Newmsg->outMailHdr = BoxID;
	Newmsg->data = iddata;
	Replymsg = Newmsg;
	lockServerTableLock->Acquire();
	
	if (kernelServerLocks[id].Serverlock == NULL) {
		printf("Error: The lock has been deleted\n");
		BoxID.from = 0;
		BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		lockServerTableLock->Release();
		return;
	}
	lockServerTableLock->Release();
	int re = kernelServerLocks[id].Serverlock->Acquire();
	if (re == 2){
		BoxID.from = 0;
		BoxID.length = strlen(nack2) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack2); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
	}
}

void releseLock(int id,  PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Release Lock Fail!";
  char *ack = "Release Lock Finish!";
  char *nack2 = "You are not the lock owner!";
  char *nack3 = "Release and Destroy lock!";
	if (id < 0) {
		printf("Error: the lock id %d is invalid\n", id);
		return;
	}
	lockServerTableLock->Acquire();
	if (kernelServerLocks[id].Serverlock == NULL) {
		printf("Error: The lock has been deleted\n");
		BoxID.from = 0;
		BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		lockServerTableLock->Release();
		return;
	}
	BoxID.from = 0;
	BoxID.length = strlen(ack) + 1;
	ACKInfor *Newmsg = new ACKInfor;
	Newmsg->outPktHdr = MachineID;
	Newmsg->outMailHdr = BoxID;
	Replymsg = Newmsg;
	int re = kernelServerLocks[id].Serverlock->Release();
	if (kernelServerLocks[id].Serverlock->getStatus() == FREE && kernelServerLocks[id].isToBeDeleted) {
		// No threads are waiting
		// delete the lock
		
		ServerLock *lock = kernelServerLocks[id].Serverlock;
		delete lock;
		kernelServerLocks[id].Serverlock = NULL;
		kernelServerLocks[id].addr = NULL;
		lockServerMap->Clear(id);
		re = 3;
	}
	 lockServerTableLock->Release();
	if(re == 1){
	bool success = postOffice->Send(MachineID, BoxID, ack); 
    		if ( !success ) {
      		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      		interrupt->Halt();
    		}
  }
  else if(re == 2){
  	BoxID.from = 0;
		BoxID.length = strlen(nack2) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack2); 
    		if ( !success ) {
      		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      		interrupt->Halt();
    		}
  }
  else if(re ==3)
  {
		BoxID.from = 0;
		BoxID.length = strlen(nack3) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack3); 
    		if ( !success ) {
      		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      		interrupt->Halt();
    		}
  }
}

void createCV(char* CVName, PacketHeader MachineID, MailHeader BoxID){
	ServerCondition *CV;
	bool exist = false;
	int id;
	int i;
	char *nack = "CV already exist!";
	conditionServerTableLock->Acquire();
	CV = new ServerCondition(CVName);
	for(i=0; i<MAX_CVS; i++){
		if (kernelServerCVs[i].Servercondition!=NULL && !strcmp(kernelServerCVs[i].Servercondition->name, CV->name)){
			exist = true;
		  break;
		}
	}
	if (exist == true){
		delete CV;
		printf("CV %s already exist", CVName);
		BoxID.from = 0;
		char *iddata = new char[25];   
  	sprintf(iddata, "%d", i);
		BoxID.length = strlen(iddata) + 1;
		bool success = postOffice->Send(MachineID, BoxID, iddata); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
    delete[] iddata;
	}
	else{
		id = conditionServerMap->Find();
		if (id < 0) {
		printf("Error: the number of locks reaches the maximum value\n");
		return;
		}
		char *iddata = new char[25];  
  	sprintf(iddata, "%d", id);
		kernelServerCVs[id].Servercondition = CV;
		kernelServerCVs[id].isToBeDeleted = FALSE;
		kernelServerCVs[id].addr = currentThread->space;
		BoxID.from = 0;
		BoxID.length = strlen(iddata) + 1;
		bool success = postOffice->Send(MachineID, BoxID, iddata); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
    delete[] iddata;
	}
	conditionServerTableLock->Release();
}

void destoryCV(int id, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Destroy CV Fail!";
	if (id < 0) {
		printf("Error: the CV id %d is invalid\n", id);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	char *ack = "Destory CV Finish!";
	conditionServerTableLock->Acquire();
	if (kernelServerCVs[id].Servercondition == NULL) {
		printf("Error: The lock has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		conditionServerTableLock->Release();
		return;
	}
	if (kernelServerCVs[id].Servercondition->IsQueueEmpty()) {
		// No threads are waiting
		// delete the lock
		kernelServerCVs[id].Servercondition = NULL;
		kernelServerCVs[id].addr = NULL;
		conditionServerMap->Clear(id);
	}else {
		// Some one is waiting
		// delete it later
		kernelServerCVs[id].isToBeDeleted = TRUE;
	}
	BoxID.from = 0;
	BoxID.length = strlen(ack) + 1;
	bool success = postOffice->Send(MachineID, BoxID, ack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
	conditionServerTableLock->Release();
}

void signalCV(int cid, int lid, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Signal CV Fail!";
	char *ack = "Signal CV Finish!";
	char *nack2 = "You are not the lock owner!";
	char *nack3 = "You signal a client wait on other lock!";
	if (cid < 0) {
		printf("Error: the CV id %d is invalid\n", cid);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	if (lid < 0) {
		printf("Error: the CV id %d is invalid\n", lid);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	ServerLock *lock;
	lockServerTableLock->Acquire();
	if (kernelServerLocks[lid].Serverlock == NULL) {
		printf("Error: The lock has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		lockServerTableLock->Release();
		return;
	}
	lock = kernelServerLocks[lid].Serverlock;
	conditionServerTableLock->Acquire();
	lockServerTableLock->Release();
	if (kernelServerCVs[cid].Servercondition == NULL) {
		printf("Error: The condition variable has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		conditionServerTableLock->Release();
		return;
	}
	ServerCondition *condition = kernelServerCVs[cid].Servercondition;
	int re = condition->Signal(lid);
	if (condition->IsQueueEmpty() && kernelServerCVs[cid].isToBeDeleted) {
		delete condition;
		kernelServerCVs[cid].Servercondition = NULL;
		kernelServerCVs[cid].addr = NULL;
		conditionServerMap->Clear(cid);
	}
	conditionServerTableLock->Release();
	if (re == 1){
		BoxID.from = 0;
		BoxID.length = strlen(nack2) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack2); 

  	if ( !success ) {
   		printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
	}
	else if(re == 2){
		BoxID.from = 0;
		BoxID.length = strlen(ack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, ack); 

  	if ( !success ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
	}
	else if(re == 3){
		BoxID.from = 0;
		BoxID.length = strlen(nack3) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack3); 

  	if ( !success ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
	}
}

void waitCV(int cid, int lid, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Wait CV Fail!";
	char *ack = "Waiting on CV !";
	char *nack2 = "You wait on a different lock!";
	char *nack3 = "Can't waiting, you still have the lock!";
	if (lid < 0 ||cid<0) {
		printf("Error: the lock id %d is invalid\n", lid);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
    BoxID.length = strlen(nack3) + 1;
		bool success2 = postOffice->Send(MachineID, BoxID, nack3); 

  	if ( !success2 ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
		return;
	}
	char *iddata = new char[25];   
  sprintf(iddata, "%d", lid);
  BoxID.from = 0;
  BoxID.length = strlen(iddata) + 1;
	ACKInfor *Newmsg = new ACKInfor;
	Newmsg->outPktHdr = MachineID;
	Newmsg->outMailHdr = BoxID;
	Newmsg->data = iddata;
	Replymsg = Newmsg;
	ServerLock *lock;
	lockServerTableLock->Acquire();
	if (kernelServerLocks[lid].Serverlock == NULL) {
		printf("Error: The lock has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
    BoxID.length = strlen(nack3) + 1;
		bool success2 = postOffice->Send(MachineID, BoxID, nack3); 

  	if ( !success2 ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
		lockServerTableLock->Release();
		return;
	}
	lock = kernelServerLocks[lid].Serverlock;
	conditionServerTableLock->Acquire();
	lockServerTableLock->Release();
	if (kernelServerCVs[cid].Servercondition == NULL) {
		printf("Error: The condition variable has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
    BoxID.length = strlen(nack3) + 1;
		bool success2 = postOffice->Send(MachineID, BoxID, nack3); 

  	if ( !success2 ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
		conditionServerTableLock->Release();
		return;
	}
	ServerCondition *condition = kernelServerCVs[cid].Servercondition;
	conditionServerTableLock->Release();
  int re = condition->Wait(lid);
  if(re == 1){
  	BoxID.from = 0;
		BoxID.length = strlen(ack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, ack); 

  	if ( !success ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
	}
	else if(re == 2){
		BoxID.from = 0;
		BoxID.length = strlen(nack2) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack2); 

  	if ( !success ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
  	
  	BoxID.length = strlen(nack3) + 1;
		bool success2 = postOffice->Send(MachineID, BoxID, nack3); 

  	if ( !success2 ) {
    	printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    	interrupt->Halt();
  	}
	}
  delete[] iddata;
}

void broadcastCV(int cid, int lid, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Broadcast CV Fail!";
	char *ack = "Broadcast CV finish!";
	if (cid < 0) {
		printf("Error: the condition id %d is invalid\n", cid);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	if (lid < 0) {
		printf("Error: the lock id %d is invalid\n", lid);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	ServerLock *lock;
	lockServerTableLock->Acquire();
	if (kernelServerLocks[lid].Serverlock == NULL) {
		printf("Error: The lock has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		lockServerTableLock->Release();
		return;
	}
	lock = kernelServerLocks[lid].Serverlock;
	conditionServerTableLock->Acquire();
	lockServerTableLock->Release();
	if (kernelServerCVs[cid].Servercondition == NULL) {
		printf("Error: The condition variable has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		conditionServerTableLock->Release();
		return;
	}
	ServerCondition *condition = kernelServerCVs[cid].Servercondition;
	condition->Broadcast(lid);
	if (kernelServerCVs[cid].isToBeDeleted) {
		delete condition;
		kernelServerCVs[cid].Servercondition = NULL;
		kernelServerCVs[cid].addr = NULL;
		conditionServerMap->Clear(cid);
	}
	conditionServerTableLock->Release();
	BoxID.from = 0;
	BoxID.length = strlen(ack) + 1;
	bool success = postOffice->Send(MachineID, BoxID, ack); 

  if ( !success ) {
    printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
    interrupt->Halt();
  }
}

void createMV(int size, char* MVname, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Create MV Fail!";
	int i;
	//char *ack = "Broadcast CV success!";
	if (size < 0) {
		printf("Error: the MV size %d is invalid\n", size);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	int* MV = new int[size];
	for(int j=0; j<size; j++){
		MV[j] = -1;
	}
	bool exist = false;
	int id;
	MVServerTableLock->Acquire();
	for(i=0; i<MAX_MVS; i++){
		if (kernelServerMVs[i].name != NULL && !strcmp(kernelServerMVs[i].name,MVname)){
			exist = true;
		  break;
		}
	}
	if (exist == true){
		delete[] MV;
		printf("MV %s already exist", MVname);
		BoxID.from = 0;
		char *iddata = new char[25];
		if(kernelServerMVs[i].size == size){   
  		sprintf(iddata, "%d", i);
			BoxID.length = strlen(iddata) + 1;
			bool success = postOffice->Send(MachineID, BoxID, iddata); 
      
    	if ( !success ) {
    	  printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
     	 interrupt->Halt();
   	 }
  	}
  	else{
  		 BoxID.from = 0;
	 		 BoxID.length = strlen(nack) + 1;
				bool success = postOffice->Send(MachineID, BoxID, nack); 

   		 if ( !success ) {
     		 printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      		interrupt->Halt();
   		 } 
  	}
    delete[] iddata;
	}
	else{
		id = MVServerMap->Find();
		if (id < 0) {
		printf("Error: the number of MVs reaches the maximum value\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
		}
		char *iddata = new char[25];  
  	sprintf(iddata, "%d", id);
		kernelServerMVs[id].MV = MV;
		kernelServerMVs[id].size = size;
		kernelServerMVs[id].name = MVname;
		BoxID.from = 0;
		BoxID.length = strlen(iddata) + 1;
		bool success = postOffice->Send(MachineID, BoxID, iddata); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
    delete[] iddata;
	}
	MVServerTableLock->Release();
}

void destoryMV(int id, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Destroy MV Fail!";
	if (id < 0) {
		printf("Error: the MV id %d is invalid\n", id);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	char *ack = "Destory success!";
	MVServerTableLock->Acquire();
	if (kernelServerMVs[id].MV == NULL) {
		printf("Error: The MV has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		MVServerTableLock->Release();
		return;
	}
	int *MV = kernelServerMVs[id].MV;
	delete[] MV;
	kernelServerMVs[id].MV = NULL;
	kernelServerMVs[id].size = 0;
	MVServerMap->Clear(id);
	BoxID.from = 0;
	BoxID.length = strlen(ack) + 1;
	bool success = postOffice->Send(MachineID, BoxID, ack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
	MVServerTableLock->Release();
}

void getMV(int id, int slot, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Get MV Fail!";
	if (id < 0 || slot>=kernelServerMVs[id].size || slot < 0 ) {
		printf("Error: the MV id %d is invalid\n", id);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	int value;
	MVServerTableLock->Acquire();
	if (kernelServerMVs[id].MV == NULL) {
		printf("Error: The MV has been deleted\n");
	  BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		MVServerTableLock->Release();
		return;
	}
	value = kernelServerMVs[id].MV[slot];
	char* reply = new char[25];   
  sprintf(reply, "%d", value);
  BoxID.from = 0;
  BoxID.length = strlen(reply) + 1;
	bool success = postOffice->Send(MachineID, BoxID, reply); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
	MVServerTableLock->Release();
	delete[] reply;
}

void setMV(int id, int slot, int value, PacketHeader MachineID, MailHeader BoxID){
	char *nack = "Set MV Fail!";
	if (id < 0 || slot>=kernelServerMVs[id].size || slot < 0) {
		printf("Error: the MV id %d is invalid\n", id);
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		return;
	}
	
	char* ack = "MV changed value";
	MVServerTableLock->Acquire();
	if (kernelServerMVs[id].MV == NULL) {
		printf("Error: The MV has been deleted\n");
		BoxID.from = 0;
	  BoxID.length = strlen(nack) + 1;
		bool success = postOffice->Send(MachineID, BoxID, nack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
		MVServerTableLock->Release();
		return;
	}
	kernelServerMVs[id].MV[slot] = value;
	BoxID.from = 0;
	BoxID.length = strlen(ack) + 1;
	bool success = postOffice->Send(MachineID, BoxID, ack); 

    if ( !success ) {
      printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
      interrupt->Halt();
    }
	MVServerTableLock->Release();
}


void servertest() {
	PacketHeader outPktHdr, inPktHdr;
  MailHeader outMailHdr, inMailHdr;
  char buffer[MaxMailSize];
  string parts[5];
  
	while(true){
		cout<<"Start receiving"<<endl;
		for(int i=0; i<MaxMailSize; i++){
			buffer[i] = '\0';
		}
		postOffice->Receive(0, &inPktHdr, &inMailHdr, buffer);
		printf("Got \"%s\" from %d, box %d\n",buffer,inPktHdr.from,inMailHdr.from);
    fflush(stdout);
    outPktHdr.to = inPktHdr.from;
    outMailHdr.to = inMailHdr.from;
    currentID = outPktHdr.to;
    currentBox = outMailHdr.to;
    //parse the message
    istringstream buff((string)buffer);
  	int i = 0;
 		while(buff>>parts[i]){
  		i++;
  	}
  	string input = parts[0];
  		if (input == "CL"){
  			size_t length;
  			char *newbuffer = new char[20];
  			length = parts[1].copy(newbuffer,strlen(parts[1].data()),0);
  			newbuffer[length] = '\0';
  			createLock(newbuffer, outPktHdr, outMailHdr);
  		}
  		else if (input == "DL")
  			destoryLcok(atoi((char*)parts[1].c_str()), outPktHdr, outMailHdr);
  		else if (input == "AL")
  			acquireLcok(atoi((char*)parts[1].c_str()), outPktHdr, outMailHdr);
  		else if (input == "RL")
  			releseLock(atoi((char*)parts[1].c_str()), outPktHdr, outMailHdr);
  		else if (input == "CC"){
  			size_t length;
  			char *newbuffer = new char[20];
  			length = parts[1].copy(newbuffer,strlen(parts[1].data()),0);
  			newbuffer[length] = '\0';
  			createCV(newbuffer, outPktHdr, outMailHdr);
  		}
  		else if (input == "DC")
  			destoryCV(atoi((char*)parts[1].c_str()), outPktHdr, outMailHdr);
  		else if (input == "SC")
  			signalCV(atoi((char*)parts[1].c_str()), atoi((char*)parts[2].c_str()), outPktHdr, outMailHdr);
  		else if (input == "WC")
  			waitCV(atoi((char*)parts[1].c_str()), atoi((char*)parts[2].c_str()), outPktHdr, outMailHdr);
  	  else if (input == "BC")
  	  	broadcastCV(atoi((char*)parts[1].c_str()), atoi((char*)parts[2].c_str()), outPktHdr, outMailHdr);
  		else if (input == "CM"){
  			size_t length;
  			char *newbuffer = new char[20];
  			length = parts[2].copy(newbuffer,strlen(parts[2].data()),0);
  			newbuffer[length] = '\0';
  			cout<<newbuffer<<endl;
  			createMV(atoi((char*)parts[1].c_str()),newbuffer, outPktHdr, outMailHdr);
  		}
  		else if (input == "DM")
  			destoryMV(atoi((char*)parts[1].c_str()), outPktHdr, outMailHdr);
  		else if (input == "SM")
  			setMV(atoi((char*)parts[1].c_str()), atoi((char*)parts[2].c_str()), atoi((char*)parts[3].c_str()), outPktHdr, outMailHdr);
  		else if (input == "GM")
  			getMV(atoi((char*)parts[1].c_str()), atoi((char*)parts[2].c_str()), outPktHdr, outMailHdr);
  	
	}
}
